import tkinter
from typing import Dict, Union, Callable


# ================= tools ====================

def get_attrs_disposable(attrs: Dict[str, str], att: Union[list, str], default=None) -> str:
    """ 在字典中获取值，并把值删除。

    值的名字可以用空格隔开起别名。例如 'text title'，如果字典中存在其中任意一个都会获取值。并全部删除。
    """
    if isinstance(att, list):
        att = ' '.join(att)
    res = get_attrs(attrs, att, default=default)
    del_attrs(attrs, att)
    return res


def get_attrs(attrs: Dict[str, str], att: str, default=None) -> str:
    """ 从 Dict[str,str] 中获取属性，可以用空格分割多个属性名来实现属性别名。
    """
    if attrs is None or att is None:
        return default
    att = att.split(' ')
    for tag in att:
        if tag in attrs:
            return attrs.get(tag)
    return default


def del_attrs(attrs: Dict[str, str], att: str):
    """ 从 Dict[str,str] 中删除属性，一样可以空格分隔属性名。
    """
    for k in att.split(' '):
        if k in attrs:
            del attrs[k]


def parse_var(window: 'TkxWindow', var_str: str) -> tkinter.Variable:
    """ 根据一个 变量名=值 或 变量名?值 或 变量名 这样的表达式获取值。
    如果表达式包含 = ，则获取变量的同时把变量值设置为后面的数。
    如果表达式包含 ? ，则获取变量的时候，如果变量存在则直接获取，不存在则用后面的值创建。
    """
    var_str = var_str.strip()
    if '=' in var_str:
        v = [i.strip() for i in var_str.split('=')]
        var = window.get_var(v[0])
        var.set(v[1])
        return var
    if '?' in var_str:
        v = [i.strip() for i in var_str.split('?')]
        return window.get_var(v[0], v[1])
    else:
        if var_str in window.vars:
            return window.vars[var_str]
        else:
            raise Exception(f"变量 {var_str} 不存在，需要加上 ? 或者 = 声明一下。")


def get_command(window: 'TkxWindow', command: str) -> Callable:
    """ 把xml中的命令字符串转换成可调用函数。
    命令字符串中如果用@开头则表示直接就是可执行代码，会自动加上self变量，并用分号分隔语句
    """
    if command.startswith('@'):
        env: dict = {
            'self': window
        }
        command = command[1:].replace(';', '\n')

        def command_func(*args, **kwargs):
            env['args'] = args
            env['kwargs'] = kwargs
            exec(command, env)

        return command_func
    else:
        return getattr(window, command)
